package com.test.crawler.utils;

import org.apache.commons.lang.StringUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * chromedriver下载地址：http://npm.taobao.org/mirrors/chromedriver/
 */
public abstract class ChromeDriverDownloader<T extends AbstractCrawlerEntry> {

  private static final Logger LOGGER = LoggerFactory.getLogger(ChromeDriverDownloader.class);

  private String driverPath;

  public ChromeDriverDownloader() {
    //driverPath = "/Users/apple/chromedriver";
    System.out.println("####" + System.getProperty("user.dir"));
    driverPath = System.getProperty("user.dir") + "/chromedriver";
    System.out.println("####" + driverPath);
  }


  public WebDriver setUp(CrawlerIn crawlerIn) {
    ChromeDriverService driverService = new ChromeDriverService.Builder().usingDriverExecutable(new File(driverPath)).usingAnyFreePort().build();
    try {
      driverService.start();
    } catch (IOException e) {
      LOGGER.error("driverService:加载失败", e.getMessage());
    }

    //无头模式
    ChromeOptions chromeOptions = new ChromeOptions();
    if (crawlerIn.isHeadless()) {
      chromeOptions.addArguments("--headless");
      chromeOptions.addArguments("--window-size=1920,1080");
      chromeOptions.addArguments("--start-maximized");
      chromeOptions.addArguments("--no-sandbox");//解决 unknown error: DevToolsActivePort file doesn't exist
      chromeOptions.addArguments("--disable-dev-shm-usage");//解决  unknown error: DevToolsActivePort file doesn't exist
      chromeOptions.addArguments("--disable-setuid-sandbox");
      chromeOptions.addArguments("--disable-dev-shm-usage");//解决 UnknownError: session deleted because of page crash from tab crashed
    }
    chromeOptions.addArguments("user-agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'");
    DesiredCapabilities desiredCapabilities = DesiredCapabilities.chrome();
    desiredCapabilities.setCapability(ChromeOptions.CAPABILITY, chromeOptions);

    return new ChromeDriver(driverService, desiredCapabilities);
  }

  protected Object getExtractByValue(WebDriver webDriver, ExtractBy extractBy) {
    String value = extractBy.value();
    String[] paths = value.split("###");
    for (String path : paths) {
      try {
        Object propertyValue;
        if (!extractBy.multi()) {//一条数据
            if (extractBy.click()){
                WebElement element = webDriver.findElement(By.cssSelector(extractBy.clickCss()));
                element.click();
                Thread.sleep(1000);
            }
          WebElement productPropertyElement = webDriver.findElement(By.cssSelector(path));
          if (StringUtils.isEmpty(extractBy.attr())) {
            propertyValue = productPropertyElement.getText();
          } else {
            propertyValue = productPropertyElement.getAttribute(extractBy.attr());
          }
        } else {//多条数据
          List<WebElement> productPropertyElements = webDriver.findElements(By.cssSelector(path));
          List<String> result = new ArrayList<>();
          productPropertyElements.forEach(productPropertyElement -> {
            String productPropertyTemp;
            if(StringUtils.isNotEmpty(extractBy.cssProperty())){
              productPropertyTemp = productPropertyElement.getCssValue(extractBy.cssProperty());
              if (StringUtils.isNotEmpty(productPropertyTemp)){
                try {
                  productPropertyTemp=productPropertyTemp.split("\"")[1];
                }catch (Exception e1){
                  LOGGER.error("extractBy.cssProperty:加载失败", e1.getMessage());
                }
              }
            }else if (StringUtils.isEmpty(extractBy.attr())) {
              productPropertyTemp = productPropertyElement.getText();
            }else {
              productPropertyTemp = productPropertyElement.getAttribute(extractBy.attr());
            }
            result.add(productPropertyTemp);
          });
          propertyValue = result;
        }
        return propertyValue;
      } catch (Exception e) {//元素不存在
        System.out.println("当前元素不存在:" + path);
        continue;
      }
    }
    return null;

  }

  protected void setValue(Object obj, String propertyName, Object propertyValue) {
    try {
      Field field = obj.getClass().getDeclaredField(propertyName);
      field.setAccessible(true);
      field.set(obj, propertyValue);
    } catch (Exception e) {
      e.printStackTrace();
      LOGGER.error("元素设值失败", e.getMessage());
    }
  }

  public abstract T craw(WebDriver webDriver, String url);

  public List<T> execute(CrawlerIn crawlerIn) {
    WebDriver webDriver = setUp(crawlerIn);
    List<T> result = null;
    try {
      result = new ArrayList<>();
      for (String url : crawlerIn.getUrl()) {
        T pageResult = craw(webDriver, url);
        result.add(pageResult);
      }
      return result;
    } catch (Exception e) {
      e.printStackTrace();
      LOGGER.error("craw error for :"+crawlerIn.toString(),e);
      return null;
    } finally {
      webDriver.quit();
    }
  }
}
